package airhockey.spel;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class AirhockeySpeelveld extends SurfaceView implements SurfaceHolder.Callback {
	private int widthFrame; //breedte van de frame van het speelveld
	private int heightFrame; //hoogte van de frame van het speelveld
	
	private Peddel peddelGebruiker; //de peddel van de gebruiker
	private Puk puk; //de bal op het scherm waarmee gespeeld wordt
	private AirhockeyThread airhockeyThread; //airhockey thread met de game loop
	private boolean gameIsStarted = false; //spel start als de bal gestoten wordt
	private Middenlijn middenlijn; //middenlijn van het spel
	
	/**
	 * Maak een nieuwe airhockey speelveld
	 * @param context
	 */
	public AirhockeySpeelveld(Context context) {
		super(context);
		//deze klasse linken met de surface holder callback
		getHolder().addCallback(this);
		//teken de peddel van de gebruiker
		peddelGebruiker = new Peddel(BitmapFactory.decodeResource(getResources(), R.drawable.paddle), 100, 350);
		//NOTE: de puk en middenlijn worden getekend in de methode surfaceCreated()
	}


	/**
	 * Event listener als vinger de peddel aanraakt
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//de peddel touched
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			peddelGebruiker.handleActionDown((int)event.getX(), (int)event.getY());
			puk.setDragged(false);
		}
		//de peddel touched en dragged
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			if (peddelGebruiker.isTouched()) {
				updatePaddleCoordinates(event);
				//de snelheid verhogen als de puk weggeslagen wordt
				if (hasCollisionPukPeddel()) {
					puk.setDragged(true);
				}
			}
		}
		//touch losgelaten
		if (event.getAction() == MotionEvent.ACTION_UP) {
			if (peddelGebruiker.isTouched()) {
				peddelGebruiker.setTouched(false);
				puk.setDragged(false);
			}
		}
		//check peddel heeft de middenlijn aangeraakt
		if (peddelGebruikerhasHitMiddenlijn(peddelGebruiker)) {
			int yPos = heightFrame/2 + peddelGebruiker.getRadius();
			peddelGebruiker.setY(yPos);
		}
		return true;
	}

	/**
	 * Update the paddle coordinates on the screen
	 * @param event
	 */
	private void updatePaddleCoordinates(MotionEvent event) {
		int xPos = (int) event.getX();
		int yPos = (int) event.getY();
		int radius = peddelGebruiker.getRadius();
		
		//peddel heeft de top v.d. canvas aangeraakt
		if (hasHitTopCanvas(yPos, radius)) {
			yPos = radius;
		}
		//peddel heeft de bodem v.d. canvas aangeraakt
		if (hasHitBottomCanvas(yPos, radius)) {
			yPos = heightFrame - radius;
		}
		//peddel heeft de linkerkant canvas aangeraakt
		if (hasHitLeftCanvas(xPos, radius)) {
			xPos = radius;
		}
		//peddel heeft de rechterkant canvas aangeraakt
		if (hasHitRightCanvas(xPos, radius)) {
			xPos = widthFrame - radius;
		}
		
		//update de coordinaten van de peddel
		peddelGebruiker.setX(xPos);
		peddelGebruiker.setY(yPos);
	}

	
	/**
	 * Check of de peddel de middenlijn heeft aangeraakt
	 * @param peddel
	 * @return
	 */
	private boolean peddelGebruikerhasHitMiddenlijn(Peddel peddel) {
		int lijn = heightFrame/2;
		return (peddel.getY() - peddel.getRadius() < lijn);
	}


	//************************************************************
	//Canvas 
	//Check if canvas has been hit
	//************************************************************
	private boolean hasHitTopCanvas(int yPos, int radius) {
		return (yPos - radius < 0);
	}
	/**
	 * Checkt of de bodem van de canvas is aangeraakt
	 * @param yPos
	 * @param radius
	 * @return
	 */
	private boolean hasHitBottomCanvas(int yPos, int radius) {
		return (yPos + radius > heightFrame);
	}
	/**
	 * Checkt of de linkerkant van de canvas is geraakt
	 * @param x
	 * @param radius
	 * @return
	 */
	private boolean hasHitLeftCanvas(int x, int radius) {
		return (x - radius < 0);
	}
	private boolean hasHitRightCanvas(int x, int radius) {
		 return (x + radius > widthFrame);
	}
	
	//************************************************************
	//Peddel
	//Check if paddle has been hit
	//************************************************************
	
	/**
	 * Update de bewegingen van de puk
	 * zodra die tegen de canvas 
	 */
	public void updatePhysicsPuk() {
		int x = puk.getX();
		int y = puk.getY();
		
		//beweeg de bal alleen als de bal voor het eerst is aangeraakt
		if (gameIsStarted) {
			x += puk.getxVel(); //horizontaal bewegen
			y += puk.getyVel(); //verticaal bewegen
			puk.setX(x);
			puk.setY(y);
		}
		
		//afhandelen puk en peddel botsing
		if (hasCollisionPukPeddel()) {
	        gameIsStarted = true;
	        changeDirectionPuk();
	    }
		
		//afhandelen puk als die canvas raakt
		handlePukHitCanvas();
	}
	
	/**
	 * Verander richting en snelheid puk bij aanraking van de peddel
	 */
	private void changeDirectionPuk() {
		//source: http://beginwithjava.blogspot.com/2010/08/more-collision-detection-bouncing-right.html
		int xVel = puk.getxVel();
		int yVel = puk.getyVel();
		
		// If we hit on the left side, go left (negative x velocity).
		if ((puk.getX()+(puk.getRadius()/2)) < (peddelGebruiker.getX()+(peddelGebruiker.getRadius()/2))){ 
			if (puk.isDragged()) xVel -= 3; 
			xVel=(0-Math.abs(xVel));
		}
        // If we hit on the right side, go right (positive x velocity).
        if ((puk.getX()+(puk.getRadius()/2)) > (peddelGebruiker.getX()+(peddelGebruiker.getRadius()/2))){
        	if (puk.isDragged()) xVel += 3;
        	xVel=Math.abs(xVel);
        }
        // If we hit on the top, go up.
        if ((puk.getY()+(puk.getRadius()/2)) < (peddelGebruiker.getY()+(peddelGebruiker.getRadius()/2))){ 
        	if (puk.isDragged()) yVel -= 3;
        	yVel=(0-Math.abs(yVel)); 
        }
        // If we hit on the bottom, go down.
        if ((puk.getY()+(puk.getRadius()/2)) > (peddelGebruiker.getY()+(peddelGebruiker.getRadius()/2))){
        	if (puk.isDragged()) yVel += 3;
        	yVel=Math.abs(yVel);
        }
		puk.setxVel(xVel);
		puk.setyVel(yVel);
	}
	
	/**
	 * De actie van de puk afhandelen als die tegen de randen van de canvas stoot
	 */
	private void handlePukHitCanvas() {
		boolean hasHitTopCanvas = hasHitTopCanvas(puk.getY(), puk.getRadius());
		boolean hasHitBottomCanvas = hasHitBottomCanvas(puk.getY(), puk.getRadius());
		boolean hasHitLeftCanvas = hasHitLeftCanvas(puk.getX(), puk.getRadius());
		boolean hasHitRightCanvas = hasHitRightCanvas(puk.getX(), puk.getRadius());
		
		int y = 0;
		int x = 0;
		
		if (hasHitTopCanvas || hasHitBottomCanvas) {
			if (hasHitTopCanvas) {
 				y = puk.getRadius();
 				puk.setyVel(-Puk.yVelDefault); //snelheid verminderen
			} else {
				y = heightFrame - puk.getRadius();
				puk.setyVel(Puk.yVelDefault); //snelheid verminderen
			}
			puk.setY(y);
			
			//richting draaien puk
			int yVel = puk.getyVel();
			puk.setyVel(yVel * -1);
		}
		
		if (hasHitLeftCanvas || hasHitRightCanvas) {
			if (hasHitLeftCanvas) {
				x = puk.getRadius();
				puk.setxVel(-Puk.xVelDefault);
			} else {
				x = widthFrame - puk.getRadius();
				puk.setxVel(Puk.xVelDefault);
			}
			puk.setX(x);
			//richting draaien puk
			int xVel = puk.getxVel();
			puk.setxVel(xVel *= -1);
		}
	}


	/**
	 * Check if there is a collision with the puk and the peddel
	 * @return
	 */
	private boolean hasCollisionPukPeddel() {
		boolean collision = false;
		float distanceXSquare = (puk.getX() - peddelGebruiker.getX()) * (puk.getX() - peddelGebruiker.getX());
		float distanceYSquare = (puk.getY() - peddelGebruiker.getY()) * (puk.getY() - peddelGebruiker.getY());
		int distance = (int) Math.sqrt(distanceXSquare + distanceYSquare);
		int r1Pr2 = (int) (puk.getRadius() + peddelGebruiker.getRadius());
	    
		//Collided or just touched
		if (distance < r1Pr2 || distance == r1Pr2) {
	        collision = true;    
	    }
		return collision;
	}
	
	
	/**
	 * Tekenen van de objecten op het speelveld canvas
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.WHITE);
		puk.draw(canvas);
		peddelGebruiker.draw(canvas);
		middenlijn.draw(canvas);
		drawGoals(canvas);
	}  
	
	/**
	 * De puk wordt hier op het canvas getekend
	 */
	public void surfaceCreated(SurfaceHolder holder) {
		//haal de canvas op en initialiseer de hoogte en breedte
		Rect surfaceFrame = holder.getSurfaceFrame();
		widthFrame = surfaceFrame.width();
		heightFrame = surfaceFrame.height();
		
		//definieer de middenlijn
		middenlijn = new Middenlijn(widthFrame, heightFrame);
		
		//definieer de puk in het midden onderin scherm
		puk = new Puk(widthFrame/2, heightFrame-130);


		//create and start the airhockey game loop thread
		airhockeyThread = new AirhockeyThread(this);
		airhockeyThread.setRunning(true);
		airhockeyThread.start();
	}
	/**
	 * Tekenen van een doel
	 * @param canvas
	 */
	private void drawGoals(Canvas canvas) {
		Paint paint = new Paint();
		paint.setColor(Color.RED);
		//teken de bovenste doel
		canvas.drawRect(225, 0, 100, 20, paint);		
	}


	/**
	 * When the surface is destroyed, stop the running game loop thread
	 */
	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		airhockeyThread.setRunning(false);
		
		while (retry) {
			try {
				airhockeyThread.join();
				retry = false;
			} catch (InterruptedException e) {
			}
		}
	}
	
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
	}
}
